/**
 * @file bsp_aht21_handler.c
 * @author liufeng (liufeng@injoinic.com)
 * @brief aht21 handler with FreeRTOS.
 * @version 0.1
 * @date 2024-11-06
 *
 * @copyright Copyright (c) 2024  injoinic
 *
 */

/*==============================================================================
                     ##### How to use this driver #####
  ==============================================================================
    1. the aht21HandlerTask function have been realized in this module, user
       should creat a aht21HandlerTask, and give aht21Handler construct argument
       when creat the task, example have been given in FreeRTOS_app.c
    2. the aht21ReadTask must be realized by user, example have been given in
       the end of this file.
  ==============================================================================*/

/* Inlcude ------------------------------------------------------------------ */

#include "bsp_aht21_handler.h"
#include "stdio.h"

#ifdef USE_FULL_ASSERT
#define assert_failed(char, int)              \
    do {                                      \
        printf("Error:%s,%d\r\n", char, int); \
        while (1) {                           \
        }                                     \
    } while (0)
#define assert_param(expr) \
    if (!expr)             \
    assert_failed(__FILE__, __LINE__)
#else
#define assert_param(expr) ((void)0U)
#endif

#define OS_MAX_DELAY 0xffffffffUL // FreeRTOS max delay

/* Declaration -------------------------------------------------------------- */

aht21_handler_type aht21Handler = {.is_init = false}; // aht21Handler instance
aht21_handler_input_func handler_input_func = {0};    // handler input function table
aht21_driver_input_func driver_input_func = {0};      // driver input function table

/* Defination --------------------------------------------------------------- */

/**
 * @brief  construct aht21_Handler and aht21 instance.
 * @param[in] handler_instance aht21 handler instance.
 * @param[in] input_arg input_arg construct argument @struct aht21_input_func.
 * @return 0: successful
 *         1: failed
 */
uint8_t aht21Handler_construct(
    aht21_handler_type* handler_instance, aht21_input_func* input_arg
)
{
    /* check parameter */
    assert_param(handler_instance);
    assert_param(input_arg);

    /* construct aht21 Handler */
    handler_input_func.pf_delay_ms = input_arg->pf_delay_ms;
    handler_input_func.pf_get_tick = input_arg->pf_get_tick;
    handler_input_func.pf_queue_create = input_arg->pf_queue_create;
    handler_input_func.pf_queue_get = input_arg->pf_queue_get;
    handler_input_func.pf_queue_put = input_arg->pf_queue_put;

    handler_instance->func_port = &handler_input_func;

    /* construct aht21 driver */
    driver_input_func.pf_iic_init = input_arg->pf_iic_init;
    driver_input_func.pf_iic_deinit = input_arg->pf_iic_deinit;
    driver_input_func.pf_iic_write_bytes = input_arg->pf_iic_write_bytes;
    driver_input_func.pf_iic_read_bytes = input_arg->pf_iic_read_bytes;
    driver_input_func.pf_disable_irq = input_arg->pf_disable_irq;
    driver_input_func.pf_enable_irq = input_arg->pf_enable_irq;
    driver_input_func.pf_delay_ms = input_arg->pf_delay_ms;

    aht21_construct(handler_instance->aht21_instance, &driver_input_func);
    return 0;
}

/**
 * @brief init aht21_Handler run environment and aht21 instance(aht21_init
 *        function will init the gpio and bsp_delay、read aht21 ID).
 * @param[in] handler_instance
 * @return 0: successful
 *         1: failed
 */
uint8_t aht21Handler_init(aht21_handler_type* handler_instance)
{
    /* check parameter */
    assert_param(handler_instance);

    /* init aht21 instance */
    uint8_t res = 0;
    res = handler_instance->aht21_instance->pf_aht21_init(handler_instance->aht21_instance);
    if (res) {
        return 1;
    }

    /* init aht21Handler run environment */
    handler_instance->event_queue_handle =
        handler_instance->func_port->pf_queue_create(5, sizeof(aht21HandlerEventEnum));
    handler_instance->data_queue_handle =
        handler_instance->func_port->pf_queue_create(5, sizeof(aht21TempAndHumiType));
    // makesure creat the queue successfully
    assert_param(handler_instance->event_queue_handle);
    assert_param(handler_instance->data_queue_handle);

    handler_instance->is_init = true;
    return 0;
}

/**
 * @brief deinit aht21_Handler run environment and aht21 instance(aht21_deinit
 *        function will deinit the gpio and bsp_delay).
 * @param[in] handler_instance
 * @return 0: successful
 *         1: failed
 */
uint8_t aht21Handler_deinit(aht21_handler_type* handler_instance)
{
    /* check parameter */
    assert_param(handler_instance);
    assert_param(handler_instance->is_init);

    /* deinit aht21 instance */
    handler_instance->aht21_instance->pf_aht21_deinit(handler_instance->aht21_instance);

    /* deinit aht21Handler run environment */
    // TODO

    handler_instance->is_init = false;
    return 0;
}

/**
 * @brief aht21Handler Task function.
 * @param[in] argument this parameter must be @struct aht21_input_func type.
 */
void aht21HandlerTask(void* argument)
{
    // all function pointer (for construct function), get from Task function argument
    assert_param(argument);
    aht21_input_func* construct_arg = (aht21_input_func*)argument;

    aht21_type aht21_instance;
    aht21Handler.aht21_instance = &aht21_instance;
    aht21Handler_construct(&aht21Handler, construct_arg); // construct
    aht21Handler_init(&aht21Handler);                     // init

    aht21HandlerEventEnum event_msg;                      // get temp、humi or both
    aht21TempAndHumiType thi_data;                        // temprature and humidity data

    while (1) {
        aht21Handler.func_port->pf_queue_get(
            aht21Handler.event_queue_handle, &event_msg, OS_MAX_DELAY
        );

        // take a new measurement
        uint8_t res = 0;
        res = aht21Handler.aht21_instance->pf_aht21_getTempAndHumi(aht21Handler.aht21_instance);
        // judge whether the measure is ok or not
        if (res == 0) {
            // update data timestamp
            aht21Handler.timestamp = aht21Handler.func_port->pf_get_tick();
            // send temprature and humidity data to queue
            thi_data.event = event_msg;
            thi_data.temprature = aht21Handler.aht21_instance->temprature;
            thi_data.humidity = aht21Handler.aht21_instance->humidity;
            aht21Handler.func_port->pf_queue_put(
                aht21Handler.data_queue_handle, &thi_data, OS_MAX_DELAY
            );
        }
    }
}

/* -------------------------------------------------------------------------- */
/*                            aht21ReadTask example                           */
/* -------------------------------------------------------------------------- */
/* void aht21ReadTask(void* argument)
{
    aht21HandlerEventEnum event_msg; // get temp、humi or both
    aht21TempAndHumiType thi_data;   // temprature and humidity data
    if (aht21Handler.is_init == false) {
        // aht21 need about 100ms to power-on init.
        vTaskDelay(100);
    }

    while (1) {
        event_msg = GET_BOTH; // depend on user
        xQueueSend(aht21Handler.event_queue_handle, &event_msg, portMAX_DELAY);

        xQueueReceive(aht21Handler.data_queue_handle, &thi_data, portMAX_DELAY);
        printf("the data timestamp is %d\r\n", aht21Handler.timestamp);

        switch (thi_data.event) {
        case GET_TEMP:
            printf("Temprature is %f\r\n\r\n", thi_data.temprature);
            break;
        case GET_HUMI:
            printf("Humidity is %f%%\r\n\r\n", thi_data.humidity);
            break;
        case GET_BOTH:
            printf("Temprature is %f\r\n", thi_data.temprature);
            printf("Humidity is %f%%\r\n\r\n", thi_data.humidity);
            break;
        default:
            break;
        }
        vTaskDelay(1000);
    }
} */
